﻿using System;
using System.Windows.Markup;
using System.Windows;
using System.ComponentModel;

// Taken from the Mvvm helpers of Mark Smith, http://www.julmar.com/blog/mark/2009/04/17/WPFMVVMHelperLibraryWPFMVVMTestability.aspx
// original namespace is JulMar.Windows.Markup
namespace Elca.MvvmHelpers
{
    /// <summary>
    /// This provides a simple way to establish a ViewModel for a View through a markup extension
    /// </summary>
    public class ViewModelCreatorExtension : MarkupExtension
    {
        /// <summary>
        /// The Type of the view model to create
        /// </summary>
        public Type ViewModelType { get; set; }

        /// <summary>
        /// Default constructor
        /// </summary>
        public ViewModelCreatorExtension()
        {
        }

        /// <summary>
        /// Parameterized constructor
        /// </summary>
        /// <param name="type">Type to create</param>
        public ViewModelCreatorExtension(Type type)
        {
            ViewModelType = type;
        }

        /// <summary>
        /// Returns an object to represent the ViewModel.
        /// </summary>
        /// <returns>
        /// The object value to set on the property where the extension is applied. 
        /// </returns>
        /// <param name="serviceProvider">Object that can provide services for the markup extension.</param>
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            try
            {
                object vm = ViewModelType != null ? Activator.CreateInstance(ViewModelType) : null;

                // If it's a ViewModel type, and the target is a top-level Window, then subscribe to the close request
                // event and close the window if the view model raises the event.
                BaseViewModel jvm = vm as BaseViewModel;
                if (jvm != null)
                {
                    IProvideValueTarget ipvt = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
                    if (ipvt != null)
                    {
                        Window winTarget = ipvt.TargetObject as Window;
                        if (winTarget != null)
                        {
                            jvm.CloseRequest += ((s, e) =>
                                                     {
                                                         try
                                                         {
                                                             winTarget.DialogResult = e.Result;
                                                         }
                                                         catch (InvalidOperationException)
                                                         {
                                                             // Raised if this was displayed via Show() vs. ShowDialog
                                                             winTarget.Close();
                                                         }
                                                     });
                            jvm.ActivateRequest += ((s, e) => winTarget.Activate());

                            BaseViewModel.IsInDesignMode = DesignerProperties.GetIsInDesignMode(winTarget);
                        }
                    }

                }

                return vm;
            }
            catch
            {
                // If we are in design mode, then don't allow the exception to propogate out -- it kills the design surface.
                if ((bool)(DesignerProperties.IsInDesignModeProperty.GetMetadata(typeof(DependencyObject)).DefaultValue)) 
                    return null;
                
                // Otherwise throw it
                throw;
            }
        }
    }
}